package com.meida.module.arc.provider.service.impl;

import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.meida.common.base.entity.EntityMap;
import com.meida.common.base.utils.FlymeUtils;
import com.meida.common.mybatis.base.service.impl.BaseServiceImpl;
import com.meida.common.mybatis.model.ResultBody;
import com.meida.common.mybatis.query.CriteriaQuery;
import com.meida.common.mybatis.query.CriteriaSave;
import com.meida.common.utils.ApiAssert;
import com.meida.common.utils.JsonUtils;
import com.meida.module.arc.client.entity.ArcCategorySecond;
import com.meida.module.arc.client.entity.ArcField;
import com.meida.module.arc.client.entity.ArcSecondField;
import com.meida.module.arc.client.enums.QueryTypeEnum;
import com.meida.module.arc.client.vo.ArcSecondFieldJson;
import com.meida.module.arc.provider.mapper.ArcSecondFieldMapper;
import com.meida.module.arc.provider.service.ArcCategorySecondService;
import com.meida.module.arc.provider.service.ArcFieldService;
import com.meida.module.arc.provider.service.ArcSecondFieldService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 二级分类字段配置接口实现类
 *
 * @author flyme
 * @date 2022-08-07
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class ArcSecondFieldServiceImpl extends BaseServiceImpl<ArcSecondFieldMapper, ArcSecondField> implements ArcSecondFieldService {

    @Autowired
    private ArcFieldService arcFieldService;

    @Autowired
    private ArcCategorySecondService arcCategorySecondService;

    @Override
    public ResultBody beforeAdd(CriteriaSave cs, ArcSecondField asf, EntityMap extra) {
        return ResultBody.ok();
    }



    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public ResultBody beforePageList(CriteriaQuery<ArcSecondField> cq, ArcSecondField asf, EntityMap requestMap) {
      cq.orderByDesc("asf.createTime");
      return ResultBody.ok();
    }

    @Override
    public ResultBody upOrDown(Map var1) {
        ApiAssert.isNotEmpty("字段id不能为空", var1.get("secondFieldId"));
        ApiAssert.isNotEmpty("移动类型不能为空", var1.get("type"));
        //排序为从小到大排   type为1为上移  2为下移 3拖动
        Long secondFieldId = NumberUtil.parseLong(var1.get("secondFieldId").toString());
        Integer type = NumberUtil.parseInt(var1.get("type").toString());
        if (type != 1 && type != 2 && type != 3) {
            ApiAssert.failure("移动类型只能为上移或下移");
        }
        Object fromIndex = var1.get("fromIndex");
        Object toIndex = var1.get("toIndex");
        if (type == 3) {
            ApiAssert.isNotEmpty("拖动角标来源不能为空", var1.get("fromIndex"));
            ApiAssert.isNotEmpty("拖动角标目标不能为空", var1.get("toIndex"));
        }
        ArcSecondField fd = this.getById(secondFieldId);
        CriteriaQuery<ArcSecondField> query = new CriteriaQuery<ArcSecondField>(ArcSecondField.class);
        query.lambda().eq(ArcSecondField::getCategorySecondId, fd.getCategorySecondId());
        List<ArcSecondField> list = this.list(query);
        if (type == 3) {//单独处理拖动问题
            int fromIndexInt = Integer.parseInt(fromIndex.toString());
            int toIndexInt = Integer.parseInt(toIndex.toString());
            if (fromIndexInt == toIndexInt) {
                ApiAssert.failure("移动前后角标不能相等");
            }
            if (fromIndexInt >= list.size() || fromIndexInt < 0 || toIndexInt >= list.size() || toIndexInt < 0) {
                ApiAssert.failure("移动前后角标不能越界");
            }
            List<ArcSecondField> updateObj = new ArrayList<>();
            ArcSecondField toArcField = new ArcSecondField();
            toArcField.setSecondFieldId(secondFieldId);
            toArcField.setSeq(toIndexInt);
            updateObj.add(toArcField);
            if (fromIndexInt < toIndexInt) {//下移
                for (int i = fromIndexInt + 1; i <= toIndexInt; i++) {
                    ArcSecondField obj = new ArcSecondField();
                    obj.setSecondFieldId(list.get(i).getSecondFieldId());
                    obj.setSeq(i-1);
                    updateObj.add(obj);
                }
            } else {//上移
                for (int i = toIndexInt; i < fromIndexInt; i++) {
                    ArcSecondField obj = new ArcSecondField();
                    obj.setSecondFieldId(list.get(i).getSecondFieldId());
                    obj.setSeq(i+1);
                    updateObj.add(obj);
                }
            }
            this.saveOrUpdateBatch(updateObj);
            return ResultBody.ok();
        }
        int sourceIndex = -1;
        int targetIndex = -1;
        for (int i = 0; i < list.size(); i++) {
            ArcSecondField obj = list.get(i);
            if (obj.getSecondFieldId().equals(secondFieldId)) {
                if (type == 1) {//上移
                    if (i == 0) {
                        return ResultBody.failed("无法上移");
                    } else {
                        sourceIndex = i;
                        targetIndex = i - 1;
                    }
                } else if (type == 2) {//下移
                    if (i == list.size() - 1) {
                        return ResultBody.failed("无法下移");
                    } else {
                        sourceIndex = i;
                        targetIndex = i + 1;
                    }
                }
            }
        }
        if (sourceIndex < 0 || targetIndex < 0) {
            return ResultBody.failed("移动错误");
        }
        Long targetId = list.get(sourceIndex).getSecondFieldId();
        list.get(sourceIndex).setSecondFieldId(list.get(targetIndex).getSecondFieldId());
        list.get(targetIndex).setSecondFieldId(targetId);
        List<ArcSecondField> updateObj = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            ArcSecondField obj = new ArcSecondField();
            obj.setSecondFieldId(list.get(i).getSecondFieldId());
            obj.setSeq(i);
            updateObj.add(obj);
        }
        this.saveOrUpdateBatch(updateObj);
        return ResultBody.ok();
    }

    @Override
    public ResultBody saveOrUpdate(EntityMap requestMap){
        Long categorySecondId = requestMap.getLong("categorySecondId");
        ApiAssert.isNotEmpty("二级分类id不能为空",categorySecondId);
        ArcCategorySecond arcCategorySecond = this.arcCategorySecondService.getById(categorySecondId);
        String fields = requestMap.get("fields");
        QueryWrapper<ArcSecondField> arcSecondFieldQueryWrapper = new QueryWrapper<>();
        arcSecondFieldQueryWrapper.lambda().eq(ArcSecondField::getCategorySecondId,categorySecondId);
        this.remove(arcSecondFieldQueryWrapper);
        String secondCategoryName = requestMap.get("cnName");
        this.arcCategorySecondService.update(new UpdateWrapper<ArcCategorySecond>().lambda()
                .eq(ArcCategorySecond::getCategorySecondId,categorySecondId)
                .set(ArcCategorySecond::getCnName,secondCategoryName));
        if(FlymeUtils.isEmpty(fields)){
            return ResultBody.ok();
        }
        List<ArcSecondFieldJson> secondFields = JsonUtils.json2list(fields, ArcSecondFieldJson.class);
        ApiAssert.isNotEmpty("二级查询字段解析失败",secondFields);
        List<ArcSecondField> secondFieldList = new ArrayList<>();
        AtomicInteger atomicInteger = new AtomicInteger(0);
        secondFields.forEach(item->{
            ApiAssert.isNotEmpty("字段id存在空值",item.getFieldId());
            ArcField arcField = arcFieldService.getById(item.getFieldId());
            ApiAssert.isNotEmpty(String.format("字段【%s】查询类型为空",arcField.getFieldCnName()),item.getQueryType());
            ApiAssert.isNotEmpty(String.format("字段【%s】查询值为空",arcField.getFieldCnName()),item.getQueryVal());
            ApiAssert.isNotEmpty("配置查询字段不存在",item.getFieldId());
            ArcSecondField secondField = new ArcSecondField();
            secondField.setCategoryId(arcCategorySecond.getCategoryId());
            secondField.setCategorySecondId(categorySecondId);
            secondField.setColumnLength(arcField.getColumnLength());
            secondField.setDataType(arcField.getDataType());
            secondField.setDefaultValue(arcField.getDefaultValue());
            secondField.setDictCode(arcField.getDictCode());
            secondField.setFieldCnName(arcField.getFieldCnName());
            secondField.setFieldName(arcField.getFieldName());
            secondField.setFieldId(arcField.getFieldId());

            secondField.setInType(arcField.getInType());
            secondField.setQueryType(item.getQueryType());
            secondField.setQueryVal(item.getQueryVal());
            secondField.setSeq(atomicInteger.getAndIncrement());
            secondFieldList.add(secondField);
            //arcField.getDataType() 值类型1字符串2数字
            //arcField.getInType() 著录类型1文本框2数字框3日期框4下拉框5文本域6弹出框
            if(!Arrays.asList("unitId","isUse","isStore","isDestory","isCompilation").contains(arcField.getFieldName())) {
                switch (arcField.getInType()) {
                    case 1:
                        if (arcField.getDataType().intValue() == 1) {
                            //文本  只能为等于
                            if (arrUnContainsVal(item.getQueryType(), QueryTypeEnum.QUERY_TYPE_1.getCode(), QueryTypeEnum.QUERY_TYPE_2.getCode())) {
                                ApiAssert.failure(String.format("字段【%s】数据类型为字符串，著录类型为文本框，只能配置【等于,包含】", arcField.getFieldCnName()));
                            }
                        } else {
                            //数字
                            //1等于 2包含 3大于 4小于 5介于 6大于等于 7小于等于
                            if (!NumberUtil.isNumber(item.getQueryVal())) {
                                ApiAssert.failure(String.format("字段【%s】数据类型为数字,但是查询值【%s】非数字", arcField.getFieldCnName(), item.getQueryVal()));
                            }
                            if (arrUnContainsVal(item.getQueryType(),
                                    QueryTypeEnum.QUERY_TYPE_1.getCode(),
                                    QueryTypeEnum.QUERY_TYPE_3.getCode(),
                                    QueryTypeEnum.QUERY_TYPE_4.getCode(),
                                    QueryTypeEnum.QUERY_TYPE_5.getCode())) {
                                ApiAssert.failure(String.format("字段【%s】数据类型为数字，著录类型为文本框，只能配置【等于,大于,小于,介于】", arcField.getFieldCnName()));
                            }
                            if (item.getQueryType().equals(QueryTypeEnum.QUERY_TYPE_5.getCode())) {
                                ApiAssert.isNotEmpty(String.format("字段【%s】查询类型为介于,但是查询结果值为空", arcField.getFieldCnName(), item.getQueryValEnd()), item.getQueryValEnd());
                                if (!NumberUtil.isNumber(item.getQueryValEnd())) {
                                    ApiAssert.failure(String.format("字段【%s】数据类型为数字,但是查询值【%s】非数字", arcField.getFieldCnName(), item.getQueryValEnd()));
                                }
                                secondField.setQueryValEnd(item.getQueryValEnd());
                            }
                        }
                        break;
                    case 2:
                        //数字
                        //1等于 2包含 3大于 4小于 5介于 6大于等于 7小于等于
                        if (!NumberUtil.isNumber(item.getQueryVal())) {
                            ApiAssert.failure(String.format("字段【%s】著录类型为数字,但是查询值【%s】非数字", arcField.getFieldCnName(), item.getQueryVal()));
                        }
                        if (arrUnContainsVal(item.getQueryType(),
                                QueryTypeEnum.QUERY_TYPE_1.getCode(),
                                QueryTypeEnum.QUERY_TYPE_3.getCode(),
                                QueryTypeEnum.QUERY_TYPE_4.getCode(),
                                QueryTypeEnum.QUERY_TYPE_5.getCode())) {
                            ApiAssert.failure(String.format("字段【%s】著录类型为数字，只能配置【等于,大于,小于,介于】", arcField.getFieldCnName()));
                        }
                        if (item.getQueryType().equals(QueryTypeEnum.QUERY_TYPE_5.getCode())) {
                            ApiAssert.isNotEmpty(String.format("字段【%s】查询类型为介于,但是查询结果值为空", arcField.getFieldCnName(), item.getQueryValEnd()), item.getQueryValEnd());
                            if (!NumberUtil.isNumber(item.getQueryValEnd())) {
                                ApiAssert.failure(String.format("字段【%s】著录类型为数字,但是查询值【%s】非数字", arcField.getFieldCnName(), item.getQueryValEnd()));
                            }
                            secondField.setQueryValEnd(item.getQueryValEnd());
                        }
                        break;
                    case 3:
                        if (arcField.getDataType().intValue() == 1) {
                            //1等于 2包含 3大于 4小于 5介于 6大于等于 7小于等于
                            if (arrUnContainsVal(item.getQueryType(),
                                    QueryTypeEnum.QUERY_TYPE_1.getCode(),
                                    QueryTypeEnum.QUERY_TYPE_3.getCode(),
                                    QueryTypeEnum.QUERY_TYPE_4.getCode(),
                                    QueryTypeEnum.QUERY_TYPE_5.getCode())) {
                                ApiAssert.failure(String.format("字段【%s】著录类型为日期，只能配置【等于,大于,小于,介于】", arcField.getFieldCnName()));
                            }
                            if (item.getQueryType().equals(QueryTypeEnum.QUERY_TYPE_5.getCode())) {
                                ApiAssert.isNotEmpty(String.format("字段【%s】查询类型为介于,但是查询结果值为空", arcField.getFieldCnName(), item.getQueryValEnd()), item.getQueryValEnd());
                                secondField.setQueryValEnd(item.getQueryValEnd());
                            }
                        } else {
                            ApiAssert.failure(String.format("字段【%s】著录类型为日期，但是数据类型为数字，请检查著录配置或联系管理员", arcField.getFieldCnName()));
                        }
                        break;
                    case 4:
                        if (arcField.getDataType().intValue() == 1) {
                            //1等于 2包含 3大于 4小于 5介于 6大于等于 7小于等于
                            if (arrUnContainsVal(item.getQueryType(),
                                    QueryTypeEnum.QUERY_TYPE_1.getCode())) {
                                ApiAssert.failure(String.format("字段【%s】著录类型为下拉框，只能配置【等于】", arcField.getFieldCnName()));
                            }
                            //TODO 检查字典值
                        } else {
                            ApiAssert.failure(String.format("字段【%s】著录类型为下拉框，但是数据类型为数字，请检查著录配置或联系管理员", arcField.getFieldCnName()));
                        }
                        break;
                    case 5:
                        if (arcField.getDataType().intValue() == 1) {
                            //文本  只能为等于
                            if (arrUnContainsVal(item.getQueryType(), QueryTypeEnum.QUERY_TYPE_1.getCode(), QueryTypeEnum.QUERY_TYPE_2.getCode())) {
                                ApiAssert.failure(String.format("字段【%s】数据类型为字符串，著录类型为文本框，只能配置【等于,包含】", arcField.getFieldCnName()));
                            }
                        } else {
                            //数字
                            //1等于 2包含 3大于 4小于 5介于 6大于等于 7小于等于
                            if (!NumberUtil.isNumber(item.getQueryVal())) {
                                ApiAssert.failure(String.format("字段【%s】数据类型为数字,但是查询值【%s】非数字", arcField.getFieldCnName(), item.getQueryVal()));
                            }
                            if (arrUnContainsVal(item.getQueryType(),
                                    QueryTypeEnum.QUERY_TYPE_1.getCode(),
                                    QueryTypeEnum.QUERY_TYPE_3.getCode(),
                                    QueryTypeEnum.QUERY_TYPE_4.getCode(),
                                    QueryTypeEnum.QUERY_TYPE_5.getCode())) {
                                ApiAssert.failure(String.format("字段【%s】数据类型为数字，著录类型为文本框，只能配置【等于,大于,小于,介于】", arcField.getFieldCnName()));
                            }
                            if (item.getQueryType().equals(QueryTypeEnum.QUERY_TYPE_5.getCode())) {
                                ApiAssert.isNotEmpty(String.format("字段【%s】查询类型为介于,但是查询结果值为空", arcField.getFieldCnName(), item.getQueryValEnd()), item.getQueryValEnd());
                                if (!NumberUtil.isNumber(item.getQueryValEnd())) {
                                    ApiAssert.failure(String.format("字段【%s】数据类型为数字,但是查询值【%s】非数字", arcField.getFieldCnName(), item.getQueryValEnd()));
                                }
                                secondField.setQueryValEnd(item.getQueryValEnd());
                            }
                        }
                        break;
                    case 6:
                        if (arcField.getDataType().intValue() == 1) {
                            //1等于 2包含 3大于 4小于 5介于 6大于等于 7小于等于
                            if (arrUnContainsVal(item.getQueryType(),
                                    QueryTypeEnum.QUERY_TYPE_1.getCode())) {
                                ApiAssert.failure(String.format("字段【%s】著录类型为下拉框，只能配置【等于】", arcField.getFieldCnName()));
                            }
                            //TODO 检查字典值
                        } else {
                            ApiAssert.failure(String.format("字段【%s】著录类型为下拉框，但是数据类型为数字，请检查著录配置或联系管理员", arcField.getFieldCnName()));
                        }
                        break;
                    default:
                        ApiAssert.failure("字段输入类型错误");
                }
            }
        });
        if(secondFieldList.size()==0){
            ApiAssert.failure("二级门类配置字段为空");
        }

        this.saveBatch(secondFieldList);
        return ResultBody.ok("配置成功");
    }

    private boolean arrUnContainsVal(Integer val,Integer... arrItem){
        if(arrItem==null||arrItem.length==0){
            return true;
        }
        if(val==null){
            return true;
        }
        if(Arrays.asList(arrItem).contains(val)){
            return false;
        }else{
            return true;
        }
    }

    @Override
    public ResultBody beforeListEntityMap(CriteriaQuery<ArcSecondField> cq, ArcSecondField t, EntityMap requestMap) {
        Long categorySecondId=cq.getLong("categorySecondId");
        cq.eq(ArcSecondField.class,"categorySecondId",categorySecondId);
        return ResultBody.ok();
    }

    public static void main(String[] args) {
        System.out.println(NumberUtil.isNumber("0.1s"));
    }

}
